﻿#include <iostream>
#include <cstring>
#include <ctime>
#include <sys/socket.h>
#include <netinet/ip_icmp.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>

#define BUFFER_SIZE 1024

unsigned short calculate_checksum(void *b, int len) {
    unsigned short *buf = (unsigned short *)b;
    unsigned int sum = 0;
    unsigned short result;

    for (sum = 0; len > 1; len -= 2)
        sum += *buf++;
    if (len == 1)
        sum += *(unsigned char *)buf;
    sum = (sum >> 16) + (sum & 0xFFFF);
    sum += (sum >> 16);
    result = ~sum;
    return result;
}

int main() {
    int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (sockfd < 0) {
        perror("Socket creation failed");
        return 1;
    }

    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 替换为服务器IP

    char buffer[BUFFER_SIZE];
    memset(buffer, 0, BUFFER_SIZE);

    struct icmphdr *icmp_hdr = (struct icmphdr *)buffer;
    icmp_hdr->type = ICMP_ECHO;
    icmp_hdr->code = 0;
    icmp_hdr->un.echo.id = getpid();
    icmp_hdr->un.echo.sequence = 1;
    icmp_hdr->checksum = 0;
    icmp_hdr->checksum = calculate_checksum(buffer, sizeof(struct icmphdr));

    ssize_t bytes_sent = sendto(sockfd, buffer, sizeof(struct icmphdr), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (bytes_sent <= 0) {
        perror("Failed to send ICMP request");
        close(sockfd);
        return 1;
    }

    std::cout << "ICMP Echo Request sent" << std::endl;

    struct sockaddr_in reply_addr;
    socklen_t addr_len = sizeof(reply_addr);
    ssize_t bytes_received = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&reply_addr, &addr_len);
    if (bytes_received <= 0) {
        perror("Failed to receive reply");
        close(sockfd);
        return 1;
    }

    struct icmphdr *reply_hdr = (struct icmphdr *)buffer;
    if (reply_hdr->type == ICMP_ECHOREPLY) {
        time_t server_time;
        memcpy(&server_time, buffer + sizeof(struct icmphdr), sizeof(server_time));
        std::cout << "Server time: " << ctime(&server_time);
    }

    close(sockfd);
    return 0;
}
